<?php
/**
 * Created by PhpStorm.
 * User: jaylen
 * Date: 2020-11-02
 * Time: 19:24
 */

namespace app\common\model\traits;

use app\api\model\mp\v1\OrderSubscribeMessage;
use app\api\model\mp\v1\TNShopOrderNotifyTemplateMessage;
use app\common\enum\OrderEnum;
use app\common\enum\OrderType;
use app\common\exception\OrderException;
use app\common\exception\ParameterException;
use app\common\model\MpApiUserToken;
use app\common\model\OrderAddress;
use app\common\model\ShopProduct as ShopProductModel;
use app\common\model\ShopProductSpecs;
use app\common\validate\IDMustBeRequire;
use app\common\validate\Order as Validate;
use app\common\service\WxPay as WxPayService;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Queue;

trait HandleUserShopOrder
{
    /**
     * 根据条件获取商店订单列表数据
     * @param array $params
     * @return array
     */
    public static function getShopOrderPaginationList(array $params)
    {
        static::validatePaginationData($params);

        // 获取当前用户的user_id
        $user_id = MpApiUserToken::getCurrentUID();

        $order_data = static::with(['product' => function($query) use ($params) {
            $query->where([['product_title','like','%'.$params['title'].'%']]);
        }])
            ->where([
                ['user_id','=',$user_id],
                ['type','=',OrderType::Shop_Order]
            ])
            ->order(['create_time' => 'DESC'])
            ->field('id,order_no,amount,status,create_time');
        if (!empty($params['type'])) {
            $type = explode(',', $params['type']);
            $order_data = $order_data->where('status','in',$type);
        }

//        $order_data = $order_data->paginate([
//            'page' => $params['page'],
//            'list_rows' => $params['limit'],
//        ], true)
//            ->withAttr('create_time_stamp', function ($value, $data) {
//                return $data['create_time'];
//            });

        $order_data = $order_data->paginate([
            'page' => $params['page'],
            'list_rows' => $params['limit'],
        ], true);

        if ($order_data->isEmpty()) {
            throw new OrderException([
                'code' => 404,
                'msg' => '订单列表数据为空',
                'errorCode' => 50004
            ]);
        }

        return $order_data->toArray();
    }

    /**
     * 根据订单id获取订单详细信息
     * @param $id
     * @return array
     */
    public static function getShopOrderDetail($id)
    {
        $validate = new IDMustBeRequire();
        if (!$validate->check(['id' => $id])) {
            throw new ParameterException([
                'msg' => $validate->getError()
            ]);
        }

        $order_data = static::with(['address', 'product','express' => function($query) {
            $query->with(['express_company']);
        }])
            ->where([
                ['id','=',$id],
                ['type','=',OrderType::Shop_Order]
            ])
            ->field('id,address_id,
                freight,order_no,transaction_id,amount,user_application_refund_reason,status,
                create_time,pay_time,delivery_time,order_end_time,create_time,refund_create_time,user_application_refund_time')
            ->find();

        if (!$order_data) {
            throw new OrderException();
        }

        $order_data = $order_data->withAttr('delivery_time_stamp', function ($value, $data) {
            if (!empty($data['delivery_time'])) {
                return $data['delivery_time'];
            }
            return 0;
        })->withAttr('create_time_stamp', function ($value, $data) {
            if (!empty($data['create_time'])) {
                return $data['create_time'];
            }
            return 0;
        })->withAttr('user_application_refund_time_stamp', function ($value, $data) {
            if (!empty($data['user_application_refund_time'])) {
                return $data['user_application_refund_time'];
            }
            return 0;
        })->append(['create_time_stamp','delivery_time_stamp','user_application_refund_time_stamp']);

        return $order_data->toArray();
    }

    /**
     * 创建图鸟商店订单
     * @param $data
     * @param $notify_url
     * @return array
     */
    public static function createTNShopOrder($data, $notify_url)
    {
        $validate = new Validate();
        if (!$validate->scene('create_tn_shop')->check($data)) {
            throw new ParameterException([
                'msg' => $validate->getError(),
            ]);
        }
        $specs_data = ShopProductModel::getSpecsDataWithOrder($data['specs_data']);
        $specs = $specs_data['specs'];

        $user_id = MpApiUserToken::getCurrentUID();
        $openid = MpApiUserToken::getCurrentTokenVar('openid');

        // TODO 运费模版
        // 设置对应的运费，暂时为0
        $freight = 0.0;
        $data['freight'] = $freight;
        $data['amount'] = $specs_data['amount'] + $freight;

        $resultOptions = (new WxPayService())->createOrder(
            '图鸟科技-' . (count($specs) > 1 ? $specs[0]['product_title'] . '等' : $specs[0]['product_title']),
            $data['amount'],
            $openid,
            $notify_url,
            ['type' => OrderType::Shop_Order]
        );

        // 添加对应的信息到数据库中
        $new_order = self::addTNShopOrder($data, $specs, $resultOptions, $user_id);

        // 把微信支付相关信息放入到缓存中
        self::saveTnShopWxPayOptionsToCache($resultOptions);

        // 把订单添加到消息队列中
        $notify_time = 1200;
        $pay_timeout_time = 1800;
//        Queue::later($notify_time, 'app\common\job\OrderPayTimeoutNotifyQueue', [
//            'order_no' => $resultOptions['order_no'],
//            'is_send_template' => 1
//        ], 'order_pay_timeout_notify_queue');
//        Queue::later($pay_timeout_time, 'app\common\job\OrderPayTimeoutHandleQueue', [
//            'order_no' => $resultOptions['order_no']
//        ], 'order_pay_timeout_handle_queue');

        return $resultOptions;
    }

    /**
     * 用户在下单页面点击提交之后没有立马支付，发送下单成功的订阅消息
     * @param $order_no 订单编号
     */
    public static function cancelTNShopOrder($order_no)
    {
        $validate = new Validate();
        if (!$validate->scene('cancel')->check(['order_no' => $order_no])) {
            throw new ParameterException([
                'msg' => $validate->getError(),
            ]);
        }

        // 根据订单编号获取订单信息
        $order_data = static::with(['user','address'])
            ->where([['order_no','=',$order_no]])
            ->find();

        if (empty($order_data)) {
            throw new OrderException();
        }
        $order_data = $order_data->toArray();

        // 发送用户下单成功消息模版
        if ($order_data['allow_submit_success_subscribe'] == 1) {
            self::sendTNShopOrderCreateSubscribeMessageToUser([
                'openid' => $order_data['user']['openid'],
                'order_no' => $order_data['order_no'],
                'title' => $order_data['title'],
                'amount' => $order_data['amount'],
                'create_time' => $order_data['create_time'],
                'address' => self::formatTNShopAddress($order_data['address'])
            ]);
        }
    }

    /**
     * 设置用户是否允许推送发货通知信息
     * @param $params
     * @return mixed
     */
    public static function setAllowDeliverySubscribe($params)
    {
        $validate = new Validate();
        if (!$validate->scene('delivery_subscribe')->check($params)) {
            throw new ParameterException([
                'msg' => $validate->getError(),
            ]);
        }

        return self::updateByOrderNo($params['order_no'],['allow_delivery_subscribe'], $params);
    }

    /**
     * 支付图鸟商店的订单
     * @param $id
     * @return mixed
     */
    public static function payTNShopOrder($id)
    {
        $order = static::where([
            ['id','=',$id],
            ['type','=',OrderType::Shop_Order],
            ['status','=',OrderEnum::CREATE_ORDER]
        ])->field('order_no')
            ->find();

        if (!$order) {
            throw new OrderException();
        }

        return self::getTnShopWxPayOptionsFromCache($order->order_no);
    }

    /**
     * 确认对应订单收到商品
     * @param $id
     * @return bool
     */
    public static function confirmTNShopOrderReceipt($id)
    {
        // 判断订单是否存在
        $order = static::where([
            ['id','=',$id],
            ['type','=',OrderType::Shop_Order],
            ['status','in',[OrderEnum::SHIP_ORDER,OrderEnum::USER_SIGN_EXPRESS]]
        ])->find();

        if (!$order) {
            throw new OrderException();
        }

        $status = $order->allowField(['status','order_end_time'])
            ->save([
                'status' => OrderEnum::ORDER_END,
                'order_end_time' => time()
            ]);

        return $status;
    }

    /**
     * 用户发起图鸟商店订单退款申请
     * @param $params
     * @return bool
     */
    public static function launchTNShopOrderRefund($params)
    {
        $validate = new Validate();
        if (!$validate->scene('application_refund_tn_shop')->check($params)) {
            throw new ParameterException([
                'msg' => $validate->getError(),
            ]);
        }

        // 判断订单是否存在
        $order_data = static::with(['user'])
            ->where([
                ['id','=',$params['id']],
                ['type','=',OrderType::Shop_Order],
                ['status','in',[OrderEnum::PAY_SUCCESS,OrderEnum::REFUND_CHANGE,OrderEnum::ORDER_END]]
            ])->find();

        if (!$order_data) {
            throw new OrderException();
        }

        // 更新订单数据
        $current_order_status = $order_data->status;
        $status = $order_data->allowField(['user_application_refund_reason','allow_refund_subscribe','refund_order_status','status','user_application_refund_time'])
            ->save([
                'user_application_refund_reason' => $params['refund_reason'],
                'allow_refund_subscribe' => $params['allow_refund_subscribe'],
                'refund_order_status' => $current_order_status,
                'status' => OrderEnum::USER_CREATE_REFUND,
                'user_application_refund_time' => time()
            ]);
        $order_data->refresh();

        if ($status) {
            // 发送消息到管理员公众号，让管理员处理退款信息
            self::sendUserLaunchShopOrderRefundToAdmin($order_data->toArray());

            // 72小时没有处理，自动退款
            $refund_timeout_time = 259200;
//            $refund_timeout_time = 60;
//            Queue::later($refund_timeout_time, 'app\common\job\OrderRefundTimeoutHandleQueue', [
//                'order_no' => $order_data->order_no
//            ], 'order_refund_timeout_handle_queue');
        }

        return $status;
    }

    /**
     * 用户手动关闭退款申请
     * @param $id
     * @return bool
     */
    public static function closeTNShopRefundApplication($id)
    {
        // 判断订单是否存在
        $order = static::where([
            ['id','=',$id],
            ['type','=',OrderType::Shop_Order],
            ['status','=',OrderEnum::USER_CREATE_REFUND]
        ])->find();

        if (!$order) {
            throw new OrderException();
        }

        // 用户取消退款之后回退到退款前的状态
        $before_refund_status = $order->refund_order_status;
        $status = $order->allowField(['status','order_end_time'])
            ->save([
                'status' => $before_refund_status,
                'order_end_time' => time()
            ]);

        return $status;
    }

    /**
     * 在下单后支付前关闭订单
     * @param $id
     * @return bool
     */
    public static function closeTNShopOrder($id)
    {
        // 先判断订单是否存在
        $order = static::where([
            ['id','=',$id],
            ['type','=',OrderType::Shop_Order],
            ['status','in',[OrderEnum::CREATE_ORDER]]
        ])
            ->find();

        if (!$order) {
            throw new OrderException();
        }

        // 删除微信支付相关信息
        self::deleteTnShopWxPayOptionsFromCache($order->order_no);

        // 更新订单信息为订单关闭
        $order->allowField(['status','order_end_time'])
            ->save([
                'status' => OrderEnum::CLOSE_ORDER,
                'order_end_time' => time()
            ]);

        // 恢复库存
        self::recoveryOrderStock($id);
    }

    /**
     * 删除指定以完成的订单
     * @param $id
     * @return bool
     */
    public static function deleteTNShopOrder($id)
    {
        // 先判断订单是否存在
        $order = static::where([
            ['id','=',$id],
            ['type','=',OrderType::Shop_Order],
            ['status','in',[OrderEnum::CLOSE_ORDER,OrderEnum::CREATE_PAY_TIMEOUT,OrderEnum::ORDER_END]]
        ])->find();

        if (!$order) {
            throw new OrderException();
        }

        return $order->delete();
    }

    /**
     * 根据订单id对商品库存进行删减
     * @param $id
     * @return bool
     */
    public static function deductOrderStock($id)
    {
        // 根据id查找出对应的specs的ID数据
        $order_product = static::with(['product' => function($query) {
            $query->field('order_id, specs_id, product_count');
        }])
            ->where('status','=',OrderEnum::CREATE_ORDER);

        $order_product = $order_product->where(function ($query) use ($id) {
            $query->whereOr([
                ['id','=',$id],
                ['order_no','=',$id]
            ]);
        })->find();
        if (empty($order_product)) {
            throw new OrderException();
        }

        $order_product = $order_product->toArray();
        // 根据specs_id和product_count对库存进行操作
        $product = $order_product['product'];
        $specs_data = [];
        foreach ($product as $p_item) {
            $specs_data[] = [
                'id' => $p_item['specs_id'],
                'stock' => Db::raw("stock-${p_item['product_count']}")
            ];
        }
        $shopProductSpecs = new ShopProductSpecs();
        $status = $shopProductSpecs->saveAll($specs_data);

        return !$status ? false : true;
    }

    /**
     * 根据订单id对商品库存进行恢复
     * @param $id
     * @return bool
     */
    public static function recoveryOrderStock($id)
    {
        // 根据id查找出对应的specs的ID数据
        // 根据id查找出对应的specs的ID数据
        $order_product = static::with(['product' => function($query) {
            $query->field('order_id, specs_id, product_count');
        }])
            ->where('status','in',[OrderEnum::PAY_ERROR,OrderEnum::CLOSE_ORDER,OrderEnum::REFUND_SUCCESS,OrderEnum::CREATE_PAY_TIMEOUT]);
        $order_product = $order_product->where(function ($query) use ($id) {
            $query->whereOr([
                ['id','=',$id],
                ['order_no','=',$id]
            ]);
        })->find();

        if (empty($order_product)) {
            throw new OrderException();
        }

        $order_product = $order_product->toArray();
        // 根据specs_id和product_count对库存进行操作
        $product = $order_product['product'];
        $specs_data = [];
        foreach ($product as $p_item) {
            $specs_data[] = [
                'id' => $p_item['specs_id'],
                'stock' => Db::raw("stock+${p_item['product_count']}")
            ];
        }
        $shopProductSpecs = new ShopProductSpecs();
        $status = $shopProductSpecs->saveAll($specs_data);

        return !$status ? false : true;
    }

    /**
     * 检查当前操作的订单是否属于当前用户
     * @param $id
     * @param $uid
     * @return bool
     */
    public static function checkOrderIsBelongsToUser($id, $uid)
    {
        $order_data = static::where([
            ['id','=',$id],
            ['user_id','=',$uid],
            ['type','=',OrderType::Shop_Order]
        ])->find();

        if (!$order_data) {
            throw new OrderException([
                'code' => 401,
                'msg' => '当前订单为非法操作',
                'errorCode' => 50005
            ]);
        }

        return true;
    }

    /**
     * 将图鸟商店订单的微信支付相关信息放入缓存
     * @param $options
     * @return bool
     */
    public static function saveTnShopWxPayOptionsToCache($options)
    {
        return Cache::store('redis')->set(
            self::generateSaveTnShopWxPayOptionsKey($options['order_no']),
            json_encode($options, JSON_UNESCAPED_UNICODE),
            self::WX_PAY_OPTIONS_EXPIRE);
    }

    /**
     * 从缓存中获取图鸟商店订单的微信支付相关信息
     * @param $order_no
     * @return mixed
     */
    public static function getTnShopWxPayOptionsFromCache($order_no)
    {
        $data = Cache::store('redis')->get(self::generateSaveTnShopWxPayOptionsKey($order_no), '');
        if (empty($data)) {
            throw new OrderException([
                'code' => 404,
                'msg' => '获取微信支付相关信息为空',
                'errorCode' => 50003
            ]);
        }

        return json_decode($data, true);
    }

    /**
     * 从缓存中删除图鸟商店订单的微信支付相关信息
     * @param $order_no
     * @return bool
     */
    public static function deleteTnShopWxPayOptionsFromCache($order_no)
    {
        return Cache::store('redis')->delete(self::generateSaveTnShopWxPayOptionsKey($order_no));
    }

    /**
     * 将订单的相关信息写入到数据库中
     * @param $data
     * @param $specs_data
     * @param $address
     * @param $wx_pay_options
     * @param $user_id
     * @return bool
     */
    private static function addTNShopOrder($data, $specs_data, $wx_pay_options, $user_id)
    {
        $static = new static();
        $static->startTrans();

        try {
            // 添加用户收货地址到数据库中
            $address = $data['address'];
            $orderAddress = OrderAddress::create([
                'user_id' => $user_id,
                'user_name' => $address['user_name'] ?? '',
                'tel_number' => $address['tel_number'] ?? '',
                'province_name' => $address['province_name'] ?? '',
                'city_name' => $address['city_name'] ?? '',
                'county_name' => $address['county_name'] ?? '',
                'detail_info' => $address['detail_info'] ?? ''
            ]);

            // 添加订单数据
            $static->allowField(['title','img_url','address_id','notes','freight','user_id','order_no', 'prepay_id', 'amount',
                'allow_submit_success_subscribe','allow_pay_timeout_subscribe','allow_pay_subscribe',
                'type','status'
            ])->save([
                'title' => count($specs_data) > 1 ? $specs_data[0]['product_title'] . '等' : $specs_data[0]['product_title'],
                'img_url' => $specs_data[0]['product_image'],
                'notes' => $data['notes'],
                'address_id' => $orderAddress->id,
                'freight' => $data['freight'],
                'user_id' => $user_id,
                'order_no' => $wx_pay_options['order_no'],
                'prepay_id' => $wx_pay_options['prepay_id'],
                'amount' => $data['amount'],
                'allow_submit_success_subscribe' => $data['allow_submit_success_subscribe'],
                'allow_pay_timeout_subscribe' => $data['allow_pay_timeout_subscribe'],
                'allow_pay_subscribe' => $data['allow_pay_subscribe'],
                'type' => OrderType::Shop_Order,
                'status' => OrderEnum::CREATE_ORDER
            ]);
            $static->refresh();

            // 同时添加订单商品信息
            $static->product()->saveAll($specs_data);

            // 对库存进行删减
            self::deductOrderStock($static->id);

            $static->commit();
        } catch (\Exception $e) {
            $static->rollback();
            throw new OrderException([
                'code' => 500,
                'msg' => '拉起微信支付失败',
                'errorCode' => 50101
            ]);
        }

        return $static->toArray();
    }

    /**
     * 发送用户发起退款要求给管理员的微信上
     * @param $data
     */
    private static function sendUserLaunchShopOrderRefundToAdmin($data)
    {
//        $oc_admin_app_id = get_wx_config('oc_admin_open_id');

        $notify_id = [
            get_wx_config('oc_admin_open_id'),
            get_wx_config('oc_development_open_id')
        ];

        foreach ($notify_id as $id) {
            (new TNShopOrderNotifyTemplateMessage())->sendOrderNotifyTemplateMessage('user_application_refund',
                $id,
                [
                    'order_no' => $data['order_no'],
                    'title' => $data['title'],
                    'user_name' => $data['user']['nick_name'],
                    'refund_amount' => $data['amount'],
                    'user_application_refund_time' => $data['user_application_refund_time'],
                    'user_application_refund_reason' => $data['user_application_refund_reason']
                ]);
        }
    }

    /**
     * 发送图鸟商店下单成功的消息模版给用户
     * @param $data
     */
    private static function sendTNShopOrderCreateSubscribeMessageToUser($data)
    {
        (new OrderSubscribeMessage())->sendOrderSubscribeMessage(
            'create',
            $data['openid'],
            [
                'order_no' => $data['order_no'],
                'title' => $data['title'],
                'amount' => $data['amount'],
                'create_time' => $data['create_time'],
                'address' => $data['address']
            ]);
    }

    /**
     * 生成保存图鸟商店订单微信支付的相关信息的key
     * @param $order_no
     * @return string
     */
    private static function generateSaveTnShopWxPayOptionsKey($order_no)
    {
        return self::WX_PAY_OPTIONS_PREFIX . $order_no;
    }

    /**
     * 格式化图鸟商店收货地址
     * @param $address
     * @return string
     */
    private static function formatTNShopAddress($address)
    {
        return ($address['province_name'] ?? '') . ($address['city_name'] ?? '') . ($address['county_name'] ?? '') . ($address['detail_info'] ?? '');
    }
}